package com.atguigu;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ClassName NotSafeDemo
 * @Author yy
 * @create 2022/9/7 18:40
 */

//并发修改异常

/*
 * 1 故障现象
 *  java.util.ConcurrentModificationException
 *
 * 2 导致原因
 * next迭代器，数据不对，总数不匹配modCount != expectedModCount
 *
 * 3 解决方案
 *  3.1 使用线程安全的类，Vector不用 (Vector是线程安全的,相当于底层也是运用synchronized)
 *  3.2 Collections.synchronizedList不用(Collections是集合工具类,底层也是运用synchronized)
 *  3.3 CopyOnWriteArrayList,Yes ,读写分离+写时复制
 *
 * 4 优化建议(同样的错误不犯第2次)
 */

/*
 * CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候，不直接往当前容器Object[]添加，
 * 而是先将当前容器Object[]进行Copy，复制出一个新的容器Object[] newElements，然后向新的容器Object[] newElements里添加元素。
 * 添加元素后，再将原容器的引用指向新的容器setArray(newElements)。
 * public boolean add(E e) {
 * final ReentrantLock lock = this.lock;
 * lock.lock();
 * try {
 * Object[] elements = getArray();
 * int len = elements.length;
 * Object[] newElements = Arrays.copyOf(elements, len + 1);
 * newElements[len] = e;
 * setArray(newElements);
 * return true;
 * } finally {
 * lock.unlock();
 * }
 * }
 * 这样做的好处是可以对CopyOnWrite容器进行并发的读，而不需要加锁，因为当前容器不会添加任何元素。
 * 所以CopyOnWrite容器也是一种读写分离的思想，读和写不同的容器。
 */

public class NotSafeDemo {
    public static void main(String[] args) {
//        listNotSafe();
//        setNotSafe();
        mapNotSafe();
    }

    private static void mapNotSafe() {
        Map<String,String> map = new ConcurrentHashMap<>();
//        Map<String,String> map = Collections.synchronizedMap(new Hashtable<>());
//        Map<String,String> map = new Hashtable<>();
//        Map<String,String> map = new HashMap<>();
        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }

    private static void setNotSafe() {
        Set<String> set = new CopyOnWriteArraySet<>();
//        Set<String> set = Collections.synchronizedSet(new HashSet<>());
//        Set<String> set = new HashSet<>();

        for (int i = 0; i < 30; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }

    private static void listNotSafe() {
        List<String> list = new CopyOnWriteArrayList<>();
//        List<String> list = Collections.synchronizedList(new ArrayList<>());
//        List<String> list = new Vector<>();
//        List<String> list = new ArrayList<>();

        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}
